﻿using System.Collections.Generic;
using UnityEngine;
using System.IO;
using UnityEditor;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System;
using UnityModule;
using MobileBaseCommon.ZlibUtility;
using System.Text;
using System.Net.NetworkInformation;

public class EditorPlatform
{
    public static string GetPlatformName()
    {
        return ApplicationPath.GetPlatformName();
    }

}
public class BuildBundles : Editor
{
    // private const string BUILD_SETTINGS = "ResourceManager/生成配置文件";
    public const string OUT_PATH = "Assetbundles";
    private static bool editorModel = false;  //开发阶段这个用true，正式包改成false

    public static void Build(bool setAbName = true)
    {
        AssetDatabase.Refresh();
        if(setAbName)
        {
            //设置资源名
            SetBundles.SetAssetBundleNames();
        }
        else{
            SetBundles.SetLuaBundleNames();
        }
    
        //打包资源
        string outputPath = Path.Combine(OUT_PATH, EditorPlatform.GetPlatformName());
        DirectoryTool.CreateDir(outputPath);        
        BuildAssetBundleOptions options;
        if (editorModel)
        {
            options = BuildAssetBundleOptions.ChunkBasedCompression;
        }
        else
        {
            options = BuildAssetBundleOptions.ChunkBasedCompression | BuildAssetBundleOptions.AppendHashToAssetBundleName | BuildAssetBundleOptions.DeterministicAssetBundle;
        }

        AssetBundleManifest manifest = BuildPipeline.BuildAssetBundles(outputPath, options, EditorUserBuildSettings.activeBuildTarget);
        if (null != manifest)
        {
            BuildSettings(manifest);
        }
    }

    public static void DeleteBuildDirectoryFiles()
    {
        DirectoryInfo oldAB = new DirectoryInfo(OUT_PATH);
        if (oldAB.Exists) oldAB.Delete(true);
    }

    public static void DeleteSABundles()
    {
        DirectoryInfo oldAB = new DirectoryInfo(Application.streamingAssetsPath + "/" + OUT_PATH);
        if (oldAB.Exists) oldAB.Delete(true);
    }

    public enum emAssetType {
        None,
        Custome,
        Full,
    }

    /// <summary>
    /// 拷贝到StreamingAssets
    /// </summary>
    /// <param name="isAllFiles">拷贝所有资源, 不判断包内资源配置</param>
    public static void CopyToStreamingAssets(emAssetType type)
    {
        Debug.Log("Copy Res :"+type.ToString());
        //先删除以前的bundle
        DirectoryInfo oldAB = new DirectoryInfo(Application.streamingAssetsPath + "/" + OUT_PATH);
        if (oldAB.Exists) oldAB.Delete(true);
        if (type == emAssetType.None) {
            return;
        }
        //拷贝bundle到streamingassets
        //当前平台资源输出路径
        DirectoryInfo pPath = new DirectoryInfo(OUT_PATH + "/" + EditorPlatform.GetPlatformName());
        if (!pPath.Exists) return;

        string zipFlagBundlePath = Path.Combine(Directory.GetCurrentDirectory(), OUT_PATH, EditorPlatform.GetPlatformName()+"zipres");
        string zipFlagStreamPath = Path.Combine(Application.streamingAssetsPath, OUT_PATH, EditorPlatform.GetPlatformName());

        string pPathStr = pPath.FullName.Replace(@"\", "/");
        int pPathStrLen = pPathStr.Length;
        //拷贝文件
        string subPath = Application.dataPath.Substring(0, Application.dataPath.Length - 6);
        var files = pPath.GetFiles("*", SearchOption.AllDirectories).Where(s => !s.Name.EndsWith(".manifest"));
        if (type == emAssetType.Custome)
        {
            //根据包内资源配置拷贝
            files = files.Where(s =>
            {
                string name = Path.GetFileNameWithoutExtension(s.FullName);
                //相对路径
                string relativelyPath = s.FullName.Replace(@"\", "/").Substring(pPathStrLen + 1, s.FullName.Length - pPathStrLen - 1);
                return name.Equals(EditorPlatform.GetPlatformName()) || name.Equals("resversion");
            });
        }

        int totalCount = files.Count();
        int index = 0;
        foreach (var item in files)
        {
            index++;
            if (item.Name.EndsWith(".downloading"))
                continue;
            EditorUtility.DisplayProgressBar("复制文件中", "进度(" + index.ToString() + "/" + totalCount.ToString() + ")", (float)index / totalCount);
            //Debug.LogError(item.FullName);
            string desPath = item.FullName.Replace(@"\", "/").Replace(subPath, Application.streamingAssetsPath + "/");
            DirectoryTool.CreateDirWithFilePath(desPath);
            File.Copy(item.FullName, desPath);
        }

        EditorUtility.ClearProgressBar();
        AssetDatabase.Refresh();
    }
    public static void ZipBundleList(byte[] bs)
    {
        //bundle列表文件压缩文件不能和资源压缩包文件放一起，
        //要和bin文件同步更新
        string m_outPath = Path.Combine(BuildBundles.OUT_PATH, EditorPlatform.GetPlatformName());
        byte[] zipdata = ZlipTool.ByteToZip(bs);
        byte[] verifyData = BitConverter.GetBytes(zipdata.Length);
        byte[] srcLen = BitConverter.GetBytes(bs.Length);

        byte[] zipfile = new byte[zipdata.Length + srcLen.Length + verifyData.Length];

        Buffer.BlockCopy(verifyData, 0, zipfile, 0, verifyData.Length);
        Buffer.BlockCopy(srcLen, 0, zipfile, verifyData.Length, srcLen.Length);

        Buffer.BlockCopy(zipdata, 0, zipfile, verifyData.Length + srcLen.Length, zipdata.Length);
        using (FileStream fs = File.Open(m_outPath + "/" + EditorPlatform.GetPlatformName() + ".zip", FileMode.Create))
        {
            fs.Write(zipfile, 0, zipfile.Length);
            fs.Close();
        }

    }
    //生成配置文件
    private static void BuildSettings(AssetBundleManifest fest, bool zip_res_support = true,bool unoin_bundle_support=false)
    {
        string outputPath = Application.dataPath.Substring(0, Application.dataPath.Length - 7) + "/" + OUT_PATH + "/" + EditorPlatform.GetPlatformName();
        //生成配置文件
        Dictionary<string, AssetBundleInfoV2> dicAllBundleInfo = new Dictionary<string, AssetBundleInfoV2>();
        long resV = (long)((DateTime.Now - new DateTime(1970, 1, 1)).TotalSeconds);

        foreach (var item in fest.GetAllAssetBundles())
        {
            string key = item.Replace("_" + fest.GetAssetBundleHash(item), "");

            AssetBundleInfoV2 info = new AssetBundleInfoV2();
            info.abNameWithHash = item;
            info.de = fest.GetAllDependencies(item);
            //场景使用断点续传
            info.breakpoint = item.EndsWith("unity")?(byte)1:(byte)0;
            info.pathType = (byte)AssetBundleInfoPathType.PreDownload;

            //下载优先级
            info.priority = 0;

            FileInfo fInfo = new FileInfo(outputPath + "/" + item);
            info.fs = fInfo.Length;

            info.md5= MD5Utility.FileToMD5(outputPath + "/" + item);

            dicAllBundleInfo[key] = info;
        }
        if (unoin_bundle_support)
        {
            UnionBundle.Merge(dicAllBundleInfo, resV);
        }
        using (MemoryStream ms = new MemoryStream())
        {
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(ms, dicAllBundleInfo);
            byte[] bs = ms.ToArray();
            using (FileStream fs = File.Open(outputPath + "/" + EditorPlatform.GetPlatformName() + ".bin", FileMode.Create))
            {
                fs.Write(bs, 0, bs.Length);
                fs.Close();
            }
            ZipBundleList(bs);
        }
        string resVersionPath = outputPath + "/" + ApplicationPath.BundleVersionFile;
        if (File.Exists(resVersionPath))
        {
            File.Delete(resVersionPath);
        }
        File.WriteAllText(resVersionPath, resV.ToString());
        
        SaveServerFile(outputPath,dicAllBundleInfo);
        EditorUtility.ClearProgressBar();
        DeleteGarbage(outputPath, fest, dicAllBundleInfo);
        DeleteEmptyDirectory(outputPath);

        if(!File.Exists(outputPath + "/" + ApplicationPath.VersionInfoFile))
        {
            File.WriteAllText(outputPath + "/" + ApplicationPath.VersionInfoFile,string.Empty);
        }        
        File.WriteAllText(outputPath + "/" + ApplicationPath.MacAddressFile,GetMacByNetworkInterface());
    }

     #region 通过NetworkInterface获取MAC地址
        /// <summary>
        /// 通过NetworkInterface获取MAC地址
        /// </summary>
        /// <returns></returns>
        public static string GetMacByNetworkInterface()
        {
            try
            {
                NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces();
                foreach (NetworkInterface ni in interfaces)
                {
                    return BitConverter.ToString(ni.GetPhysicalAddress().GetAddressBytes());
                }
            }
            catch (Exception)
            {
            }
            return "00-00-00-00-00-00";
        }
    #endregion

    /// <summary>
    /// 保存服务器需要文件
    /// </summary>
    /// <param name="outputPath"></param>
    /// <param name="dicAllBundleInfo"></param>
    public static void SaveServerFile(string outputPath,Dictionary<string, AssetBundleInfoV2> dicAllBundleInfo)
    {
        string zip_proj = "{\"assets\":{{0}}}";
        
        StringBuilder sb = new StringBuilder();
        foreach (var item in dicAllBundleInfo)
        {
            sb.Append($"\"{item.Value.abNameWithHash}\"");
            sb.Append(":{");
            sb.Append("\"md5\":");
            sb.Append($"\"{MD5Utility.GetMD5Str(item.Value.md5)}\"}},\n");
        }
        string sbStr = sb.ToString();
        string finalStr = sbStr.Substring(0,sbStr.Length - 2);
        zip_proj = zip_proj.Replace("{0}", finalStr);
        File.WriteAllText(outputPath + "/" + ApplicationPath.ProjectFile, zip_proj);
    }
    /// <summary>
    /// 删除多余的文件
    /// </summary>
    private static void DeleteGarbage(string outputPath, AssetBundleManifest manifest, Dictionary<string, AssetBundleInfoV2> dicAllBundleInfo)
    {
        List<string> lstAllBundleInfo = new List<string>();
        lstAllBundleInfo.AddRange(manifest.GetAllAssetBundles());
        //string outputPath = Path.Combine(OUT_PATH, Utility.PlatformName());
        DirectoryInfo info = new DirectoryInfo(outputPath);
        if (!info.Exists)
        {
            Debug.LogError("资源路径不存在!!!!");
            return;
        }

        string platformName = EditorPlatform.GetPlatformName().ToLower();
        string mainManifestName = platformName + ".manifest";
        FileInfo[] res = info.GetFiles("*", SearchOption.AllDirectories);
        for (int i = 0; i < res.Length; i++)
        {
            string fileName = res[i].FullName.Replace(info.FullName + "\\", "").Replace("\\", "/").ToLower();
            if (fileName.EndsWith(".bin") || 
                fileName.EndsWith(".zip") || 
                fileName.EndsWith(".flag") || 
                fileName.EndsWith(".update") || fileName.EndsWith(".patch") ||
                fileName.EndsWith(".downloading") || fileName.Equals(mainManifestName) ||
                fileName.Equals(ApplicationPath.ProjectFile) ||
                fileName.Equals(ApplicationPath.VersionInfoFile.ToLower()) )
            {
                continue;
            }
            if (fileName.EndsWith(".manifest"))
            {
                string rName = fileName.Replace(".manifest", "");
                if (!dicAllBundleInfo.ContainsKey(rName))
                {
                    File.Delete(res[i].FullName);
                }
                continue;
            }
            if (!lstAllBundleInfo.Contains(fileName))
            {
                //不在资源列表中，删除文件和对应的manifest
                string dFName = res[i].FullName;
                //File.Delete(dFName + ".manifest");
                File.Delete(dFName);
            }
        }
    }
    /// <summary>
    /// 删除空目录
    /// </summary>
    /// <param name="storagepath"></param>
    public static void DeleteEmptyDirectory(string storagepath)
    {
        DirectoryInfo dir = new DirectoryInfo(storagepath);
        DirectoryInfo[] subdirs = dir.GetDirectories("*.*", SearchOption.AllDirectories);
        foreach (DirectoryInfo subdir in subdirs)
        {
            FileSystemInfo[] subFiles = subdir.GetFileSystemInfos();
            if (subFiles.Count() == 0)
            {
                subdir.Delete();
            }
        }
    }


   


    public static void CopyResToSvn() {

        string SvnPath = @"D:\Project\FileServer\res\asset\assetbundles";
        string LocalPath = "assetbundles";
        string platform = EditorPlatform.GetPlatformName();
        string targetDir = Path.Combine(SvnPath, platform);
        string localDir= Path.Combine(LocalPath, platform);
        if (Directory.Exists(targetDir))
            Directory.Delete(targetDir, true);
        if (Directory.Exists(localDir))
            CopyDirectory(localDir, targetDir);

        Debug.Log("资源已复制到SVN");
    }

    public static void Copy30058()
    {
        string currDir = Directory.GetCurrentDirectory();
        string exedir = string.Empty;
        string pb_path = Application.dataPath.Replace("Assets", string.Empty) + "\\Proto\\";
        Directory.SetCurrentDirectory(pb_path);
        string platform = EditorPlatform.GetPlatformName();
        string startBatName = "___300058_del.bat";
        if(EditorPlatform.GetPlatformName() == "ios"){
            startBatName = "___300058_add.bat";
        }
        System.Diagnostics.Process pro = System.Diagnostics.Process.Start(pb_path + startBatName);

        pro.WaitForExit();
        Directory.SetCurrentDirectory(currDir);
    }


    public static void CopyDirectory(string sourceDirPath, string SaveDirPath)
    {
        try
        {
            //如果指定的存储路径不存在，则创建该存储路径
            if (!Directory.Exists(SaveDirPath))
            {
                //创建
                Directory.CreateDirectory(SaveDirPath);
            }
            //获取源路径文件的名称
            string[] files = Directory.GetFiles(sourceDirPath);
            //遍历子文件夹的所有文件
            foreach (string file in files)
            {
                string pFilePath = SaveDirPath + "\\" + Path.GetFileName(file);
                if (File.Exists(pFilePath))
                    continue;
                File.Copy(file, pFilePath, true);
            }
            string[] dirs = Directory.GetDirectories(sourceDirPath);
            //递归，遍历文件夹
            foreach (string dir in dirs)
            {
                CopyDirectory(dir, SaveDirPath + "\\" + Path.GetFileName(dir));
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}